package lexer

import (
	"parse/src/constants"
	"parse/src/interpreter"
	"parse/src/token"
	"parse/src/utils"
	"strconv"
	"strings"
)

// 词法分析器
type Lexer struct {
	Fn          string          // 文件名称
	Text        string          // 需要解析的内容
	Pos         *token.Position // 位置
	CurrentChar string          // 当前字符
}

// 词法分析器 实例化
func New(fn string, text string) *Lexer {
	l := &Lexer{ // 解析器的初始化
		Fn:   fn,
		Text: text,
		Pos: &token.Position{
			Idx:   -1,
			Ln:    0,  // 横为0
			Col:   -1, //
			Fn:    fn,
			FText: text,
		},
		CurrentChar: "", // 当前的字符串
	}
	// 向前走一步
	l.Advance()
	return l
}

// 词法解析器，向前走一步
func (l *Lexer) Advance() {
	// 词法解析器的位置向前走一步，记录当前的字符串
	l.Pos.Advance(l.CurrentChar)
	// 表示走到了最后一个字符串
	if l.Pos.Idx < len(l.Text) {
		l.CurrentChar = string(l.Text[l.Pos.Idx])
		return
	}
	// 没有走到最后一个字符串，把索引的字符串给currentChar
	l.CurrentChar = ""
}

// 跳过注释
func (l *Lexer) skipComments() {
	l.Advance()                 // 先向前走一步
	for l.CurrentChar != "\n" { // 不是换行符时，向前走一步
		l.Advance()
	}
	l.Advance()
}

// 制作tokens
func (l *Lexer) MakeTokens() ([]token.Token, *interpreter.Error) {
	var tokens_ []token.Token
	for l.CurrentChar != "" { // 循环获取 CurrentChar
		if l.CurrentChar == " " || l.CurrentChar == "\t" { // 等于tab键
			l.Advance() // 向前走一步
		} else if l.CurrentChar == "#" { // 为注释
			l.skipComments() // 向前走一步
		} else if strings.Index(";\n\r", l.CurrentChar) > -1 { // 为分号与换行
			// 将获取到的token（NEWLINE类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_NEWLINE, // 为新行
					PosStart: l.Pos,
				}),
			)
			l.Advance() // 向前走一步
		} else if strings.Index(constants.DIGITS, l.CurrentChar) > -1 { // 为数字
			// 将获取到的token（数字类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(l.makeNumber()))
		} else if strings.Index(constants.LETTERS, l.CurrentChar) > -1 { // 为标识符
			// 将获取到的token（单词类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(l.makeIdentifier()))
		} else if l.CurrentChar == "\"" { // 为数字
			// 将获取到的token（字符串类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(l.makeString()))
		} else if l.CurrentChar == "+" { // 为加号
			// 将获取到的token（加号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_PLUS, // +
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "-" { // 为减号
			// 将获取到的token（-号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(l.makeMinusOrArrow()))
		} else if l.CurrentChar == "*" { // 为乘号
			// 将获取到的token（乘号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_MUL, // *
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "/" { // 为除号
			// 将获取到的token（除号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_DIV, // /
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "%" { // 求余数
			// 将获取到的token（求余数类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_YU, // %
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "^" { // 为取幂
			// 将获取到的token（取幂类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_POW, // ^
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "(" { // 为左边的圆括号
			// 将获取到的token（左边圆括号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_LPAREN, // (
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == ")" { // 为右边的圆括号
			// 将获取到的token（右边圆括号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_RPAREN, // )
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "[" { // 为左边的方括号
			// 将获取到的token（左边方括号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_LSQUARE, // [
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "]" { // 为右边的方括号
			// 将获取到的token（右边方括号类型的token）放进 tokens_ 数组中去
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_RSQUARE, // ]
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else if l.CurrentChar == "!" { // 为不等于 !=
			// 将获取到的token（不等于类型的token）放进 tokens_ 数组中去
			token_, error_ := l.makeNotEquals()
			if error_ != nil {
				return tokens_, error_
			}
			tokens_ = append(tokens_, token.NewToken(token_))
		} else if l.CurrentChar == "=" { // 为赋值 与等于判断 ==
			tokens_ = append(tokens_, token.NewToken(l.makeEquals()))
		} else if l.CurrentChar == "<" { // 为小于，小于等于 <=
			tokens_ = append(tokens_, token.NewToken(l.makeLessThan()))
		} else if l.CurrentChar == ">" { // 为大于，大于等于 >=
			tokens_ = append(tokens_, token.NewToken(l.makeGreaterThan()))
		} else if l.CurrentChar == "," { // 为注释
			tokens_ = append(tokens_, token.NewToken(
				token.Token{
					Type_:    constants.TT_COMMA, // 注释
					PosStart: l.Pos,
				}),
			)
			l.Advance()
		} else {
			posStart := l.Pos.Copy()
			char := l.CurrentChar
			l.Advance()
			return tokens_, interpreter.NewError(posStart, l.Pos, "非法字符错误", char)
		}
	}
	tokens_ = append(tokens_, token.NewToken(
		token.Token{
			Type_:    constants.TT_EOF,
			PosStart: l.Pos,
		}))
	return tokens_, nil
}

// 将传进来的字符串制作成为数字
func (l *Lexer) makeNumber() token.Token {
	// 数字的字符串
	numStr := ""
	// 点的书目
	dotCount := 0
	// 开始的位置
	posStart := l.Pos.Copy()

	// 当前的字符不为空的而且当前字符是在数字与.之间的，表示是小数
	for l.CurrentChar != "" && strings.Index(constants.DIGITS+".", l.CurrentChar) > -1 {
		if l.CurrentChar == "." { // 当前为.,表为小数
			if dotCount == 1 { // .有一个
				break
			}
			// .没有，就执行点的数目加一
			dotCount++
		}
		// 数字的字符串执行把当前的字符串加到最后的数字上面去
		numStr += l.CurrentChar
		l.Advance()
	}

	// 没有小数点的情况下
	if dotCount == 0 { // 为整数,也解析成小数，让数据类型唯一
		floatR, _ := strconv.ParseFloat(numStr, 64)
		// 字符串转化为数字
		return token.Token{
			Type_:    constants.TT_FLOAT, // 小数
			Value:    floatR,
			PosStart: posStart,
			PosEnd:   l.Pos.Copy(),
		}
	} else { // 有小数点的情况下，为小数
		floatR, _ := strconv.ParseFloat(numStr, 64)
		return token.Token{
			Type_:    constants.TT_FLOAT, // 小数
			Value:    floatR,
			PosStart: posStart,
			PosEnd:   l.Pos.Copy(),
		}
	}
}

// 制作 标识符
func (l *Lexer) makeIdentifier() token.Token {
	// id字符串
	idStr := ""
	// 开始位置
	posStart := l.Pos.Copy()
	// 字符串在里面就依次添加到这个token上面去
	for l.CurrentChar != "" && strings.Index(constants.LETTERS_DIGITS, l.CurrentChar) > -1 {
		idStr += l.CurrentChar
		l.Advance()
	}
	// 定义token类型
	var tokType string
	// 某个数组中包含某个 这个词
	if utils.IsContainMapString(constants.KEYWORDS, idStr) {
		tokType = constants.TT_KEYWORD // 是关键字
	} else {
		tokType = constants.TT_IDENTIFIER // 是标识符
	}
	return token.Token{
		Type_:    tokType,
		Value:    idStr,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}
}

// 制作字符串
func (l *Lexer) makeString() token.Token {
	strings_ := ""
	// 开始的位置
	posStart := l.Pos.Copy()
	// 字符
	escapeCharacter := false
	// 向前走一步
	l.Advance()
	// 制作一个可变的集合，n为换行，t为tab键
	escapeCharacters := make(map[string]string)
	escapeCharacters["n"] = "\n"
	escapeCharacters["t"] = "\t"
	// 字符串没有结束，就一直往下找，直到找到最后一个 "，
	for l.CurrentChar != "" && (l.CurrentChar != "\"" || escapeCharacter) {
		// 字符串没有结束，就
		if escapeCharacter {
			value, exit := escapeCharacters[l.CurrentChar]
			if exit { // 存在，用得到的集合里面的值
				strings_ += value
			} else { // 不存在，用原来的char
				strings_ += l.CurrentChar
			}
		} else {
			// 当前的字符串为 "\\" 斜杠，就表明是换行的意思，
			if l.CurrentChar == "\\" {
				escapeCharacter = true
			} else {
				strings_ += l.CurrentChar
			}

		}
		l.Advance()
		escapeCharacter = false
	}
	l.Advance()
	return token.Token{
		Type_:    constants.TT_STRING, // 字符串
		Value:    strings_,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}
}

// 制作->的对象类型
func (l *Lexer) makeMinusOrArrow() token.Token {
	tokType := constants.TT_MINUS // token类型为减号
	posStart := l.Pos.Copy()
	l.Advance()
	if l.CurrentChar == ">" {
		l.Advance()
		tokType = constants.TT_ARROW // -> ,arrow箭头
	}
	return token.Token{
		Type_:    tokType,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}
}

// 制作不等于
func (l *Lexer) makeNotEquals() (token.Token, *interpreter.Error) {
	posStart := l.Pos.Copy()
	l.Advance()
	if l.CurrentChar == "=" {
		l.Advance()
		return token.Token{
			Type_:    constants.TT_NE, // 不等于的token类型
			PosStart: posStart,
			PosEnd:   l.Pos.Copy(),
		}, nil
	}
	l.Advance()
	return token.Token{}, interpreter.NewError(posStart, l.Pos, "解析错误", "不等于解析错误")
}

// 制作赋值,与 等于 判断
func (l *Lexer) makeEquals() token.Token {
	tokType := constants.TT_EQ
	posStart := l.Pos.Copy()
	l.Advance()
	if l.CurrentChar == "=" {
		l.Advance()
		tokType = constants.TT_EE
	}
	return token.Token{
		Type_:    tokType,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}
}

// 小于，小于等于
func (l *Lexer) makeLessThan() token.Token {
	tokType := constants.TT_LT
	posStart := l.Pos.Copy()
	l.Advance()

	if l.CurrentChar == "=" { // 小于等于
		l.Advance()
		tokType = constants.TT_LTE
	}
	return token.Token{
		Type_:    tokType,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}

}

// 制作大于 大于等于
func (l *Lexer) makeGreaterThan() token.Token {
	tokType := constants.TT_GT
	posStart := l.Pos.Copy()
	l.Advance()

	if l.CurrentChar == "=" { // 小于等于
		l.Advance()
		tokType = constants.TT_GTE
	}
	return token.Token{
		Type_:    tokType,
		PosStart: posStart,
		PosEnd:   l.Pos.Copy(),
	}
}
